--[[
    热更新管理服务，可以通过 debug_console 来接收对应的热更请求，并通知对应的服务热更代码
]]
local skynet = require "skynet"
require "skynet.manager"
local ServiceName = require "enum.ServiceName"
local CodeCache = require "skynet.codecache"
local lfs = require"lfs"
local tableinsert = table.insert

local logChannel = "HOT_MGR"

-- file -> modify_time
local modifyTimes = {}

-- 需要热更的所有模块根目录
local dirs = {
    "core",
    "global",
    "service",
    "modules",
    "platform",
    "enum",
    -- ... 更多可热更模块
}

local function scan_dir(path)
    for file in lfs.dir(path) do
        if file ~= "." and file ~= ".." then
            local f = path..'/'..file
            local attr = lfs.attributes(f)
            assert(type(attr) == "table")
            if attr.mode == "directory" then
                scan_dir(f)
            else
                modifyTimes[f] = attr.modification
            end
        end
    end
end

local function file2module(file)
    return (file:gsub("/", ".")):sub(1, -5)
end

local agents = {}
---@class HOT_MGR
local CMD = {}
-- 注册可热更的服务
function CMD.register(address)
    tableinsert(agents, address)
    return true
end

function CMD.remove(address)
    for i = 1, #agents do
        if agents[i] == address then
            table.remove(agents, i)
            return true
        end
    end

    return true
end

local function startHotfix(hot_module_list)
    if #hot_module_list == 0 then
        return
    end

    LLOGF(logChannel, "start hotfix, files: %s", table.dump(hot_module_list))
    CodeCache.clear()
    for i = 1, #agents do
        local agent = agents[i]
        skynet.send(agent, "hotfix", hot_module_list)
    end
    CodeCache.mode("ON")
    LLOGF(logChannel, "end hotfix, files: %s", table.dump(hot_module_list))
end

-- 热更
function CMD.hotfixModule(...)
    local hot_module_list = {}
    local hot_files = {...}
    for i = 1, #hot_files do
        local f = hot_files[i]
        if modifyTimes[f] then
            local new_modify_time = lfs.attributes(f).modification
            if new_modify_time > modifyTimes[f] then
                tableinsert(hot_module_list, file2module(f))
                modifyTimes[f] = new_modify_time
            end
        end
    end

    startHotfix(hot_module_list)
end

function CMD.hotfix()
    local hot_module_list = {}
    for f, modify_time in pairs(modifyTimes) do
        local new_modify_time = lfs.attributes(f).modification
        if new_modify_time > modify_time then
            tableinsert(hot_module_list, file2module(f))
            modifyTimes[f] = new_modify_time
        end
    end

    startHotfix(hot_module_list)
end

skynet.register_protocol({
    id = skynet.PTYPE_HOTFIX,
    name = "hotfix",
    pack = skynet.pack,
    unpack = skynet.unpack,
    dispatch = function(session, source, ...)
        -- 不会接收到 hotfix 消息
    end
})

skynet.start(function()
    -- 初始化
    for i = 1, #dirs do
        scan_dir(dirs[i])
    end

    skynet.dispatch_lua(CMD)

    skynet.register(ServiceName.HOT_MGR)
end)